/*
 * Copyright (c) 2019 - 2020 IoT Company of Midea Group.
 *
 * File Name 	    : 
 * Description	    : HAL adaptor
 *
 * Version	        : v0.1
 * Author			: 
 * Date	            : 2020/07/08  refactoring
 * History	        : 
 */

#ifndef __MS_HAL_SECURE_H__
#define	__MS_HAL_SECURE_H__

/**
 * !!! please see the config.mk to make sure your chip whether had those function !!!
 * MS_CONFIG_NT_SUPPORT
 * MS_SST
 * !!! if not, do not adapter following interfaces
 */

#ifdef __cplusplus
extern "C" {
#endif

#include "ms_osal.h"
#include "ms_hal.h"

#define MIDEA_SUCCESS                       (0)
#define MIDEA_ERR_BASE_CODE                 (-0x4D4400)  //ascii code of MD
#define MIDEA_ERR_HKDF_BAD_KEYPARAM         (MIDEA_ERR_BASE_CODE-1) /**< null key pointer or zero key byte len */
#define MIDEA_ERR_HKDF_BAD_HASHMODE         (MIDEA_ERR_BASE_CODE-2) /**< invalid underlying hash mode */
#define MIDEA_ERR_HKDF_TOO_LARGE_OUTLEN     (MIDEA_ERR_BASE_CODE-3) /**< byte length of out key too large */
#define MIDEA_ERR_HKDF_NULL_OUT_BUF         (MIDEA_ERR_BASE_CODE-4) /**< null buffer of out key*/
#define MIDEA_ERR_HKDF_HMAC_ERROR           (MIDEA_ERR_BASE_CODE-5) /**< hmac operation errors*/
#define MIDEA_ERR_HKDF_HMAC_SETUP_ERROR     (MIDEA_ERR_BASE_CODE-6) /**< setup of hmac errors*/

/*!
underlying HASH algorithms of HKDF
*/
typedef enum {
    MIDEA_CRYPTO_HKDF_SHA1_MODE          = 0,    /*!< SHA1 */
    MIDEA_CRYPTO_HKDF_SHA224_MODE        = 1,    /*!< SHA224 */
    MIDEA_CRYPTO_HKDF_SHA256_MODE        = 2,    /*!< SHA256 */
    MIDEA_CRYPTO_HKDF_SHA384_MODE        = 3,    /*!< SHA384 */ 
    MIDEA_CRYPTO_HKDF_SHA512_MODE        = 4,    /*!< SHA512 */
    MIDEA_CRYPTO_HKDF_MD5_MODE           = 5,    /*!< MD5 */  //don't support
    MIDEA_CRYPTO_HKDF_HASH_NumOfModes,

}MIDEA_CRYPTO_HKDF_HASH_MODE;

/* The byte sizes of digest result for variable digest algorithms*/

#define MIDEA_CRYPTO_SHA1_DIG_LEN (20)
#define MIDEA_CRYPTO_SHA224_DIG_LEN (28)
#define MIDEA_CRYPTO_SHA256_DIG_LEN (32)
#define MIDEA_CRYPTO_SHA384_DIG_LEN (48)
#define MIDEA_CRYPTO_SHA512_DIG_LEN (64)
#define MIDEA_CRYPTO_MD5_DIG_LEN (16)
#define MIDEA_CRYPTO_MAX_DIG_LEN (64)

/**
 * \brief                HKDF: key derivation function based on HMAC(Hashed Message Authentication Code) accommodating to rfc5869
 *
 *
 * \param inKM           input keying material 
 * \param inKMlen        byte length of input keying material
 * \param salt           optional salt value, could be NULL
 * \param saltlen        byte length of salt, coulde be 0; salt is NULL or/and saltlen is 0 means not providing salt
 * \param info           optional application specific information, could be NULL
 * \param infolen        byte length of info, coulde be 0; info is NULL or/and infolen is 0 means not providing info
 * \param mode           hash mode of hkdf, it's one of these values: MIDEA_CRYPTO_HKDF_SHA1_MODE, MIDEA_CRYPTO_SHA224_DIG_LEN and MIDEA_CRYPTO_SHA256_DIG_LEN.
 * \param outkeylen      desired byte length of outkey, not exceed 255*bytelenofhashoutput of the underlying hash function
 * \param outkey         buffer to desired outkey

 * \return          0 if successful,
 *                  other values mean something wrong 
 *
 * \note           1. It means that salt is not provided if the pointer to the buffer is NULL or/and the byte length of it is 0.
 *                    It's the same to the info parameter.
 *                 2. The recommended value to mode is MIDEA_CRYPTO_SHA256_DIG_LEN.
 *                    Now this function doesn't support MIDEA_CRYPTO_SHA384_DIG_LEN and MIDEA_CRYPTO_SHA512_DIG_LEN.
 *                    These two modes required enabling the MBEDTLS_SHA512_C of mbedtls.
 *                 3. The byte length of outkey should not exceed 255*bytelenofhashoutput of the underlying hash function
 *                    e.g. for MIDEA_CRYPTO_SHA256_DIG_LEN, the maximum outkeylen is 255*32.
 *                 
 */
int ms_hal_secure_hkdf(const uint8_t *inKM, size_t inKMlen,
                      const uint8_t *salt, size_t saltlen,
                      const uint8_t *info, size_t infolen,
                      MIDEA_CRYPTO_HKDF_HASH_MODE mode,
                      size_t outkeylen, uint8_t *outkey);

/**
* @brief This function for aes ccm encrypt.
* @param[in]  key			encryption key
* @param[in]  keylen		encryption key length
* @param[in]  nonce			nonce of ccm encrypt
* @param[in]  noncelen		nonce length of ccm encrypt
* @param[in]  adata			addition data of ccm encrypt
* @param[in]  adatalen		addition data length of ccm encrypt
* @param[in]  payload		plaintext to be encrypted
* @param[in]  payloadlen	length of plaintext to be encrypted
* @param[in]  maclen		mac length of ccm encrypt
* @param[out] cipher		encrypted ciphertext
* @param[out] cipherlen		length of encrypted ciphertext
* @return  >=0 the operation completed successfully, <0 the operation failed.
*/
int ms_hal_secure_aes_ccm_genenc(uint8_t *key,  uint8_t keylen, 
                                uint8_t *nonce, uint32_t noncelen,
                                uint8_t *adata, uint32_t adatalen, 
                                uint8_t *payload, uint32_t payloadlen,
                                uint32_t maclen,
                                uint8_t *cipher, uint32_t *cipherlen);


/**
* @brief This function for aes ccm decrypt.
* @param[in]  key			decryption key
* @param[in]  keylen		decryption key length
* @param[in]  nonce 		nonce of ccm decrypt
* @param[in]  noncelen		nonce length of ccm decrypt
* @param[in]  adata 		addition data of ccm decrypt
* @param[in]  adatalen		addition data length of ccm decrypt
* @param[in]  cipher		ciphertext to be decrypted
* @param[in]  cipherlen		length of ciphertext to be decrypted
* @param[in]  maclen		mac length of ccm decrypt
* @param[out] payload		decrypt plaintext 
* @param[out] payloadlen	length of decrypt plaintext 
* @return  >=0 the operation completed successfully, <0 the operation failed.
*/
int ms_hal_secure_aes_ccm_decver(uint8_t *key, uint8_t keylen, 
                                uint8_t *nonce, uint32_t noncelen,
                                uint8_t *adata, uint32_t adatalen, 
                                uint8_t *cipher, uint32_t cipherlen,
                                uint32_t maclen,
                                uint8_t *payload, uint32_t *payloadlen);

#ifdef __cplusplus
}
#endif

#endif

